// 把对象数据类型转换成查询字符串
function queryString(obj1) {
    var str = ''
    for (var key in obj1) {
        str += key + '=' + obj1[key] + '&'
    }
    str = str.slice(0, str.length - 1)
    return str
}


// ajax的封装    ---->使用时里面传递一个对象  ajax({})
function ajax (options){
	// 判断传递的是不是一个对象
	// 检测方法   Object.prototype.toString.call（数据类型）
	if(Object.prototype.toString.call(options) !== '[object Object]'){
		// 手动报错报红
		throw new Error('传递的不是一个对象 请重新传递')
	}
	// 首先拿到 options 里面的每一个参数 用解构对象  ----> let {键名1,2,...} = 要解构的对象（options）
	// url      表示地址 
	// method   表示请求方式
	// async    表示是否异步
	// data     表示传递的数据  参数
	// headers  表示请求头
	// datatype 表示是否要解析后端数据
	// success  表示请求成功的结果 --->里面是传递的是函数
	// error    表示请求失败的结果 --->里面是传递的是函数
	let {url,method,async,data,headers,datatype,success,error} = options
	// 对里面的每一个进行验证
	// 验证 url 地址
	if(!url || typeof url !=='string'  ){
		// 手动报错报红
		throw new Error('传递的不是一个字符串 请重新传递')
	}
	// 验证 method  表示请求方式
	if(!(method === undefined || /^(get|post)$/i.test(method))){
		// 手动报错报红
		throw new Error('传递的不是get或者post请求')
	}
	// 验证 async   表示是否异步
	if(!(async === undefined || typeof async === 'boolean')) {
		// 手动报错报红
        throw new Error('你传递的不是一个布尔类型的数据')
    }
	// 验证 data    表示传递的数据   参数
	// 传递 可以没有  可以是查询字符串  可以是对象
	if(!(data === undefined || typeof data === 'string' || Object.prototype.toString.call(data) === '[object Object]')) {
		// 手动报错报红
	    throw new Error('你传递的数据不是字符串也不是对象 必须要传递一个字符串或者对象数据类型')
	}
	// 验证 headers 表示请求头
	if(!(headers === undefined || Object.prototype.toString.call(headers) === '[object Object]')){
		 throw new Error('你传递的不是一个对象数据类型 必须要传递一个对象数据类型')
	}
	// 验证 datatype 表示是否要解析后端数据
	 if (!(datatype === undefined || /^(string|json)$/i.test(datatype))) {
	        throw new Error('你必须要传递string或者json')
	    }
	// 验证 success 
	 if (!(success === undefined || typeof success === 'function')) {
	         throw new Error('你传递的不是一个函数 我需要一个函数')
	     }
    // 验证 error
	 if (!(error === undefined || typeof error === 'function')) {
	         throw new Error('你传递的不是一个函数 我需要一个函数')
	     }
	// 设计默认值
	 let _default = {
		    // 设置地址默认值
	        url: url,
			// 设置请求方式默认值
	        method: method || 'get',
			// 设置异步同步默认值
	        async: typeof async === 'boolean' ? async : true,
			// 设置传递数据默认值
	        data: data || '',
			// 设置请求头默认值
	        headers: { 'content-type': 'application/x-www-form-urlencoded', ...headers },
			// 设置 datatype 默认值 表示是否要解析后端数据
	        datatype: datatype || 'string',
			// 设置 success  表示请求成功接收后端数据的结果
	        success: success || function () { },
			// 设置 error    表示请求失败接收后端数据的结果
	        error: error || function () { }
	    }
	
	// 默认值的处理
	   // 参数  传递数据的默认处理 
	 if (typeof data === 'object') {
		 // 转换成查询字符串
	        _default.data = queryString(data)
	    }
		// 如果是get请求 并且携带了参数
	if (/^get$/i.test(_default.method) && data) {
		// 那么就拼接好在地址后面
	        _default.url = _default.url + '?' + _default.data
	    }
		
	// 发送请求
	  // 实例化一个ajax对象
	 const  xhr = new XMLHttpRequest()
	  //         请求方式           地址           是否异步
	 xhr.open(_default.method, _default.url, _default.async)
	  // 注册响应成功的函数
	 xhr.onload = () => {
		 // 接收结果
		 let res = xhr.response
		 // 判断是不是json格式
		  if (_default.datatype === 'json') {
		     try {
		       res = JSON.parse(xhr.responseText)
		        _default.success(res)
		         } catch (err) {
		                 _default.error(err)
		             }
		         } else {
		             _default.success(res)
		         }
		
	 }
	 // 请求头headers里面传递的是对象 遍历拿到每一个键和值
	  for (let k in _default.headers) {
	         xhr.setRequestHeader(k, _default.headers[k])
	     }
		 // 判断是不是get请求
	  if (/^get$/i.test(_default.method)) {
	        xhr.send()
	    } else {
	        xhr.send(_default.data)
	    }
 }
 // promise ajax封装
 
 function pAjax(options) {
     const p = new Promise(function (resolve,rejected) {
         ajax({
             url: options.url,
             data: options.data,
             async: options.async,
             method: options.method,
             headers: options.headers,
             datatype: options.datatype,
             success(res) {
                 resolve(res)
             },
             error(res) {
                 rejected(res)
             }
         })
     })
     return p
 }